/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/** \file
 * \ingroup collada
 */

#ifndef __DOCUMENTIMPORTER_H__
#define __DOCUMENTIMPORTER_H__

#include "COLLADAFWIWriter.h"
#include "COLLADAFWMaterial.h"
#include "COLLADAFWEffect.h"
#include "COLLADAFWColor.h"
#include "COLLADAFWImage.h"
#include "COLLADAFWInstanceGeometry.h"
#include "COLLADAFWController.h"
#include "COLLADAFWMorphController.h"
#include "COLLADAFWSkinController.h"
#include "COLLADAFWEffectCommon.h"

#include "BKE_object.h"
#include "BKE_constraint.h"

#include "TransformReader.h"
#include "AnimationImporter.h"
#include "ArmatureImporter.h"
#include "ControllerExporter.h"
#include "MeshImporter.h"
#include "ImportSettings.h"

struct bContext;

/** Importer class. */
class DocumentImporter : COLLADAFW::IWriter {
 public:
  //! Enumeration to denote the stage of import
  enum ImportStage {
    Fetching_Scene_data,      /* First pass to collect all data except controller */
    Fetching_Controller_data, /* Second pass to collect controller data */
  };
  /** Constructor */
  DocumentImporter(bContext *C, const ImportSettings *import_settings);

  /** Destructor */
  ~DocumentImporter();

  /** Function called by blender UI */
  bool import();

  /** these should not be here */
  Object *create_camera_object(COLLADAFW::InstanceCamera *, Scene *);
  Object *create_light_object(COLLADAFW::InstanceLight *, Scene *);
  Object *create_instance_node(Object *, COLLADAFW::Node *, COLLADAFW::Node *, Scene *, bool);
  void create_constraints(ExtraTags *et, Object *ob);
  std::vector<Object *> *write_node(COLLADAFW::Node *, COLLADAFW::Node *, Scene *, Object *, bool);
  void write_profile_COMMON(COLLADAFW::EffectCommon *, Material *);

  void translate_anim_recursive(COLLADAFW::Node *, COLLADAFW::Node *, Object *);

  /**
   * This method will be called if an error in the loading process occurred and the loader cannot
   * continue to load. The writer should undo all operations that have been performed.
   * \param errorMessage: A message containing information about the error that occurred.
   */
  void cancel(const COLLADAFW::String &errorMessage);

  /** This is the method called. The writer hast to prepare to receive data.*/
  void start();

  /** This method is called after the last write* method. No other methods will be called after
   * this.*/
  void finish();

  bool writeGlobalAsset(const COLLADAFW::FileInfo *);
  std::string get_import_version(const COLLADAFW::FileInfo *asset);

  bool writeScene(const COLLADAFW::Scene *);

  bool writeVisualScene(const COLLADAFW::VisualScene *);

  bool writeLibraryNodes(const COLLADAFW::LibraryNodes *);

  bool writeAnimation(const COLLADAFW::Animation *);

  bool writeAnimationList(const COLLADAFW::AnimationList *);

#if WITH_OPENCOLLADA_ANIMATION_CLIP
  // Please enable this when building with Collada 1.6.65 or newer (also in DocumentImporter.cpp)
  bool writeAnimationClip(const COLLADAFW::AnimationClip *animationClip);
#endif

  bool writeGeometry(const COLLADAFW::Geometry *);

  bool writeMaterial(const COLLADAFW::Material *);

  bool writeEffect(const COLLADAFW::Effect *);

  bool writeCamera(const COLLADAFW::Camera *);

  bool writeImage(const COLLADAFW::Image *);

  bool writeLight(const COLLADAFW::Light *);

  bool writeSkinControllerData(const COLLADAFW::SkinControllerData *);

  bool writeController(const COLLADAFW::Controller *);

  bool writeFormulas(const COLLADAFW::Formulas *);

  bool writeKinematicsScene(const COLLADAFW::KinematicsScene *);

  /** Add element and data for UniqueId */
  bool addExtraTags(const COLLADAFW::UniqueId &uid, ExtraTags *extra_tags);
  /** Get an extisting ExtraTags for uid */
  ExtraTags *getExtraTags(const COLLADAFW::UniqueId &uid);

  bool is_armature(COLLADAFW::Node *node);

 private:
  const ImportSettings *import_settings;

  /** Current import stage we're in. */
  ImportStage mImportStage;

  bContext *mContext;
  ViewLayer *view_layer;

  UnitConverter unit_converter;
  ArmatureImporter armature_importer;
  MeshImporter mesh_importer;
  AnimationImporter anim_importer;

  /** TagsMap typedef for uid_tags_map. */
  typedef std::map<std::string, ExtraTags *> TagsMap;
  /** Tags map of unique id as a string and ExtraTags instance. */
  TagsMap uid_tags_map;

  UidImageMap uid_image_map;
  std::map<COLLADAFW::UniqueId, Material *> uid_material_map;
  std::map<COLLADAFW::UniqueId, Material *> uid_effect_map;
  std::map<COLLADAFW::UniqueId, Camera *> uid_camera_map;
  std::map<COLLADAFW::UniqueId, Light *> uid_light_map;
  std::map<Material *, TexIndexTextureArrayMap> material_texture_mapping_map;
  std::multimap<COLLADAFW::UniqueId, Object *> object_map;
  std::map<COLLADAFW::UniqueId, COLLADAFW::Node *> node_map;
  std::vector<const COLLADAFW::VisualScene *> vscenes;
  std::vector<Object *> libnode_ob;

  std::map<COLLADAFW::UniqueId, COLLADAFW::Node *>
      root_map;  // find root joint by child joint uid, for bone tree evaluation during resampling
  std::map<COLLADAFW::UniqueId, const COLLADAFW::Object *> FW_object_map;

  std::string import_from_version;

  void report_unknown_reference(const COLLADAFW::Node &node, const std::string object_type);
};

#endif
